from functools import wraps
from inspect import signature
from typing import Any, Dict, Type, get_type_hints
import numbers
import pandas as pd
import numpy as np
from numpy.typing import DTypeLike
from numpy import dtype

class ValidationError(ValueError):
    """参数验证异常基类"""
    def __init__(self, field: str, message: str, value: Any = None):
        super().__init__(f"字段 [{field}] 验证失败: {message} (值: {value})")
        self.field = field
        self.message = message
        self.value = value

class SecurityValidationError(ValidationError):
    """安全验证异常"""
    def __init__(self, field: str, value: Any):
        super().__init__(field, "包含非法字符", value)

def validate_percentage(value: float,
                        min_value: float = 0.0,
                        max_value: float = 1.0,
                        param_name: str = "百分比参数") -> float:
    """验证百分比参数，特别处理保证金比例"""
    if not (min_value <= value <= max_value):
        raise ValidationError(
            field=param_name,
            message=f"必须在{min_value*100:.0f}%到{max_value*100:.0f}%之间（当前值：{value*100:.2f}%）",
            value=value
        )
    return value

class DataIntegrityError(ValidationError):
    """数据完整性异常"""
    def __init__(self, missing_fields: list):
        super().__init__("", f"缺失必要字段: {', '.join(missing_fields)}")
        self.missing_fields = missing_fields

import re
from functools import lru_cache

@lru_cache(maxsize=None)
def _compile_regex(pattern: str):
    """预编译正则表达式并缓存"""
    return re.compile(pattern)

def validate_stock_code(code: str) -> bool:
    """验证中国大陆股票代码格式（沪/深/北交所/科创板/创业板）
    
    参数:
        code: 股票代码（需包含交易所前缀）
        
    返回:
        bool: 通过验证返回True，否则False
        
    示例:
        >>> validate_stock_code('sh600000')   # 上证主板
        True
        >>> validate_stock_code('sh688981')   # 科创板
        True
        >>> validate_stock_code('sz300001')   # 创业板
        True
        >>> validate_stock_code('bj430090')   # 北证
        True
        >>> validate_stock_code('sz003000')   # 深市主板
        True
    """
    pattern = r'^(sh(600|601|603|605|688|689)|sz(000|001|002|003|300)|bj(43|83|87|88))\d{3,4}$'
    return bool(_compile_regex(pattern).match(code))

def validate_trading_volume(vol: int) -> bool:
    """验证成交量数据合理性"""
    return 0 <= vol <= 10**12  # 最大1万亿股

def validate_price(price: float) -> bool:
    """验证价格数据合理性"""
    return price > 0 and len(str(price).split('.')[-1]) <= 4  # 正数且小数位不超过4位

def validate_dataframe_structure(df: pd.DataFrame, required_columns: list) -> None:
    """验证DataFrame结构完整性
    
    参数:
        df: 待验证的DataFrame
        required_columns: 必须包含的字段列表
    
    异常:
        DataIntegrityError: 当缺少必要字段或字段类型不匹配时
    """
    missing = [col for col in required_columns if col not in df.columns]
    if missing:
        raise DataIntegrityError(missing)

    # 验证基础字段类型
    type_checks = {
        'open': np.number,
        'high': np.number,
        'low': np.number,
        'close': np.number,
        'volume': np.integer
    }
    for col, dtype in type_checks.items():
        if col in df.columns:
            # 类型检查
            if not isinstance(df[col].dtype, type(dtype)) and not np.issubdtype(str(df[col].dtype), str(dtype)):
                raise ValidationError(
                    field=col,
                    message=f"数据类型应为 {dtype}",
                    value=df[col].dtype
                )
            # 值范围检查
            if col == 'volume' and (df[col] < 0).any():
                raise ValidationError(
                    field=col,
                    message="成交量不能为负数",
                    value=df[col].min()
                )

def validate_timestamp_format(df: pd.DataFrame) -> None:
    """验证时间戳格式及连续性"""
    if not isinstance(df.index.dtype, type(np.datetime64)) and not np.issubdtype(str(df.index.dtype), str(np.datetime64)):
        raise ValidationError(
            field="index",
            message="索引必须是datetime类型",
            value=df.index.dtype
        )

    # 检查时间序列连续性
    time_diff = np.diff(df.index)
    if len(time_diff) == 0:
        return
    
    delta = time_diff[0]
    if not all(diff == delta for diff in time_diff):
        gaps = df.index[1:][time_diff != delta]
        raise ValidationError(
            field="index",
            message=f"时间序列存在{len(gaps)}处间隔异常",
            value=gaps
        )

def validate_ohlc_integrity(df: pd.DataFrame) -> None:
    """验证OHLC价格逻辑一致性"""
    invalid_records = df[
        (df['high'] < df['low']) |
        (df['open'] > df['high']) |
        (df['close'] > df['high']) |
        (df['open'] < df['low']) |
        (df['close'] < df['low'])
    ]
    if not invalid_records.empty:
        raise ValidationError(
            field="OHLC",
            message=f"发现{len(invalid_records)}条价格逻辑错误记录",
            value=invalid_records
        )

def validate_params(rules: Dict[str, Dict[str, Any]]):
    """参数验证装饰器工厂函数
    
    参数规则示例：
    {
        'window_size': {
            'type': int,
            'min': 1,
            'required': True
        },
        'threshold': {
            'type': numbers.Real,
            'default': 0.5,
            'min': 0,
            'max': 1
        }
    }
    """
    def decorator(func):
        sig = signature(func)
        type_hints = get_type_hints(func)
        
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 验证默认值类型
            for param in sig.parameters.values():
                if param.name in rules and param.default is not param.empty:
                    default_type = rules[param.name].get('type')
                    if default_type and not isinstance(param.default, default_type):
                        raise ValidationError(
                            f"参数 {param.name} 的默认值 {param.default} 类型错误，应为 {default_type}")
            
            bound_args = sig.bind(*args, **kwargs)
            bound_args.apply_defaults()
            
            for param_name, param_rules in rules.items():
                value = bound_args.arguments.get(param_name)
                
                # 检查必填参数
                if param_rules.get('required', False) and value is None:
                    raise ValidationError(f"{param_name} 是必填参数")
                    
                # 类型检查
                expected_type = param_rules.get('type')
                if expected_type and not isinstance(value, expected_type):
                    raise ValidationError(f"{param_name} 需要 {expected_type} 类型")
                    
                # 数值范围检查
                if isinstance(value, numbers.Number):
                    min_val = param_rules.get('min')
                    if min_val is not None and value < min_val:
                        raise ValidationError(f"{param_name} 不能小于 {min_val}")
                        
                    max_val = param_rules.get('max')  
                    if max_val is not None and value > max_val:
                        raise ValidationError(f"{param_name} 不能大于 {max_val}")
                        
            return func(*args, **kwargs)
        return wrapper
    return decorator